#include<iostream>
#include<string>
#include<cerrno>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

//const uint16_t port  =8080;
using namespace std;

string Usage(string prot)
{
    cout<<"Usage:"<<prot<<"port"<<endl;
}

// ./udp_server prot
int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        Usage(argv[1]); return 1;
    }
    uint16_t prot=atoi(argv[1]);// uint16_t --16个二进制位


    //1.创建socket,打开网络文件
    //AF_INET--IPv4 
    //SOCK_DGRAM---Supports datagrams (connectionless, unreliable messages of a fixed maximum length)
    int sock=socket(AF_INET,SOCK_DGRAM,0);

    //2.给服务器绑定端口和IP
    struct sockaddr_in local; //IPv4地址用sockaddr_in结构体表示
    local.sin_family=AF_INET;
    local.sin_port=htons(prot);//主机序列转化为网络序列

    //local.sin_addr.s_addr   1.将人识别的点分10进制字符串风格的IP转化为4字节整数IP
    //这个函数解决1、2两个问题  2.大小端问题
    local.sin_addr.s_addr=INADDR_ANY;//如果设置成某个IP,意味着只有发到这个IP的数据才会交到网络进程，这里需要所有发到该主机端口的数据

    if(bind(sock,(struct sockaddr* )&local,sizeof(local))<0)
    {
        cerr<<"bind error"<<errno<<endl; return 2;
    }

    //3.提供服务 shell
    bool quit=false;
    char buffer[1024];
    while(!quit)
    {
        struct sockaddr_in peer;
        socklen_t len=sizeof(peer);
        // receive messages from a socket
        size_t cnt=recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
        if(cnt>0)
        {
            buffer[cnt]=0;
            FILE* fp=popen(buffer,"r");//popen()函数通过创建管道、分叉和调用shell来打开进程
            string echo_hello;
            char line[1024]={0};

            while(fgets(line,sizeof(line),fp)!=NULL)
            {
                echo_hello+=line;
            }
            pclose(fp);
            cout<<"client# "<<buffer<<endl;
            //transmit a message to another socket.
            sendto(sock,echo_hello.c_str(),echo_hello.size(),0,(struct sockaddr*)&peer,len);
        }
        else{}
       
    }
    return 0;
}